﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

using BeeZ.CommonObjects.Interfaces;
using BeeZ.CommonObjects.Honey;

namespace BeeZ.Server
{
    namespace Bees
    {
        /*
        public class ListeningBee
        {
            Socket listener;
            IBear[] bears; // TODO change to List<Bear> bears

            public ListeningBee(params IBear[] args)
            {
                bears = args;
            }
            
            public void StartFlying(object o)
            {
                Console.WriteLine("{0} started flying.", this.GetType().ToString());
                listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ip = new IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), 100);

                listener.Bind(ip);
                listener.Listen(11);
                IAsyncResult result = listener.BeginAccept(new AsyncCallback(OnNewConnection), null);
                
            }

            private void OnNewConnection(IAsyncResult asyn)
            {
                ConnectionBee connectionBee = new ConnectionBee(bears);

                connectionBee.StartFlying(listener.EndAccept(asyn));

                listener.BeginAccept(new AsyncCallback(OnNewConnection), null);
            }

        }

        class ConnectionBee
        {
            public event Collect OnGetHoney;

            protected Socket client;
            //byte[] buffer;
            SimpleHoney honey;

            public ConnectionBee(params IBear[] args)
            {
                foreach (IBear b in args)
                {
                    OnGetHoney += new Collect(b.Eat);
                }
            }

            public void StartFlying(Socket s)
            {
             
                
                client = s;                
                byte[] buffer = new byte[Int32.MaxValue];
                client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), buffer);
            }

            private void OnDataReceived(IAsyncResult asyn)
            {
                byte[] buffer = (byte[])asyn.AsyncState;
                int iRx = client.EndReceive(asyn); //todo change to numOfBytes
                client.Close();

                //byte[] mybuffer = new byte[iRx];
                //Buffer.BlockCopy(buffer, 0, mybuffer, 0, iRx);//TODO
                //for (int i = 0; i < iRx; i++)
                //    mybuffer[i] = buffer[i];
                // TODO
                byte honeyType = buffer[0];                
                MemoryStream mm = new MemoryStream(buffer, 1, iRx);

                BinaryFormatter b = new BinaryFormatter();
                switch (honeyType)
                {
                    case (IHoney.SIMPLE_HONEY_TYPE):
                        honey = (SimpleHoney)b.Deserialize(mm);
                        break;
                }

                mm.Close(); // TODO
                buffer = null; //TODO
                OnGetHoney(honey); // TODO each bear east on a different thread

                return;

            }

        }

        */

        public class ServerBee
        {
            public event Collect OnGetHoney;
            private TcpListener tcpListener;
            private SimpleHoney honey;

            public ServerBee(params IBear[] args)
            {
                foreach (IBear b in args)
                {
                    OnGetHoney += new Collect(b.Eat);
                }
                this.tcpListener = new TcpListener(IPAddress.Any, 100);
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.ListenForClients));

            }

            private void ListenForClients(object o)
            {
                this.tcpListener.Start();

                while (true)
                {
                    //blocks until a client has connected to the server
                    TcpClient client = this.tcpListener.AcceptTcpClient();

                    //create a thread to handle communication
                    //with connected client
                    ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleClientComm), client);
                }

            }

            private void HandleClientComm(object client)
            {
                TcpClient tcpClient = (TcpClient)client;
                NetworkStream clientStream = tcpClient.GetStream();

                byte[] message = new byte[4096];
                int bytesRead = 0;
                
                bytesRead = clientStream.Read(message, 0, 4096);
                BinaryFormatter b = new BinaryFormatter();

                byte[] mybuffer = new byte[bytesRead];
                Buffer.BlockCopy(message, 0, mybuffer, 0, bytesRead);

                MemoryStream mm = new MemoryStream(mybuffer);

                honey = (SimpleHoney)b.Deserialize(mm);
                tcpClient.Close();
                OnGetHoney(honey);
            }


        }
    }
}